home *** CD-ROM | disk | FTP | other *** search
- unit DrBobNEW;
- {.$R+}
- {$DEFINE DEBUG}
- interface
- uses
- Classes, {$IFDEF DEBUG}StdCtrls,{$ENDIF} ScktComp;
-
- const
- MaxGroups = 256;
-
- type
- TBNNTP = class(TComponent)
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- public
- {$IFDEF DEBUG}
- StatusMemo: TMemo; { pointer to Form's Memo }
- {$ENDIF}
- procedure Connect;
- procedure JoinNewsGroup(const NewsGroup: String);
- procedure ReadArticle(ArticleNr: Integer);
- procedure Disconnect;
-
- protected
- _Socket: TClientSocket;
- procedure SocketRead(Sender: TObject; Socket: TCustomWinSocket);
- procedure SocketWrite(Sender: TObject; Socket: TCustomWinSocket);
- procedure Wait;
-
- private
- fNewsServer: String;
- published
- property NewsServer: String read fNewsServer write fNewsServer;
-
- private // newgroups
- fNumGroups: Integer;
- fNewsGroups: Array[0..MaxGroups-1] of String;
- function GetNewsGroup(Index: Integer): String;
- public
- property NewsGroups: Integer read fNumGroups;
- property NewsGroup[Index: Integer]: String read GetNewsGroup;
-
- private // articles
- fFirstArticle,fLastArticle: Integer;
- fArticles: Array of String;
- function GetArticle(Index: Integer): String;
- public
- property FirstArticle: Integer read fFirstArticle;
- property LastArticle: Integer read fLastArticle;
- property Article[Index: Integer]: String read GetArticle;
-
- private // internal
- WinSocket: TCustomWinSocket;
- Command: Integer;
- ArtNr: Integer;
- Status: String; { also NewsgroupName }
- {$IFDEF DEBUG}
- Indent: Integer;
- {$ENDIF}
- end;
-
- procedure Register;
-
- implementation
- uses
- SysUtils, Forms;
-
- const
- CmdStart = 0;
- CmdList = 1; { list newsgroups }
- CmdJoin = 2; { join newsgroup }
- CmdMess = 3; { read article # }
- CmdDone = 42; { signals ready }
- CmdQuit = 666;
-
- const
- NNTP = 119;
-
- const
- CRLF = #13#10;
-
- {$IFDEF DEBUG}
- function Space(X: Integer): String;
- begin
- Result := '';
- while X > 0 do
- begin
- Result := Result + ' ';
- Dec(X)
- end
- end {Space};
- {$ENDIF}
-
- constructor TBNNTP.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- _Socket := TClientSocket.Create(Self);
- _Socket.Port := NNTP;
- _Socket.OnRead := SocketRead;
- _Socket.OnWrite := SocketWrite;
- {$IFDEF DEBUG}
- Indent := 0;
- StatusMemo := nil;
- {$ENDIF}
- WinSocket := nil
- end {Create};
-
- destructor TBNNTP.Destroy;
- begin
- _Socket.OnRead := nil;
- _Socket.OnWrite := nil;
- //if Assigned(WinSocket) and (Command <> CmdQuit) then
- // WinSocket.SendText('QUIT'+ CRLF);
- WinSocket := nil;
- _Socket.Free;
- _Socket := nil;
- {$IFDEF DEBUG}
- StatusMemo := nil;
- {$ENDIF}
- inherited Destroy
- end {Destroy};
-
-
- function TBNNTP.GetNewsGroup(Index: Integer): String;
- begin
- if Index < MaxGroups then Result := fNewsGroups[Index]
- else Result := ''
- end {GetNewsGroup};
-
- function TBNNTP.GetArticle(Index: Integer): String;
- begin
- if (Index >= fFirstArticle) and
- ((Index-fFirstArticle) < Length(fArticles)) then
- Result := fArticles[Index-fFirstArticle]
- else Result := ''
- end {GetArticle};
-
-
- procedure TBNNTP.SocketRead(Sender: TObject; Socket: TCustomWinSocket);
- var
- i,j: Integer;
- EOD: Boolean; { end-of-data }
- begin
- {$IFDEF DEBUG}
- if Assigned(StatusMemo) then
- StatusMemo.Lines.Add(Space(Indent)+'SocketRead');
- {$ENDIF}
- WinSocket := Socket; { talk back? }
- Status := Socket.ReceiveText;
- while (Length(Status) > 0) and (Status[Length(Status)] in [#10,#13]) do
- Delete(Status,Length(Status),1);
- EOD := Pos(CRLF+'.',Copy(Status,Length(Status)-4,5)) > 0;
- // Pos(CRLF+'.',Status) > (Length(Status)-4);
- {$IFDEF DEBUG}
- if Assigned(StatusMemo) then
- begin
- if Command <> CmdMess then
- StatusMemo.Lines.Add(Space(Indent)+Status)
- else StatusMemo.Lines.Add(Space(Indent)+Copy(Status,1,Pos(#13,Status)-1));
- StatusMemo.Update; { force repaint }
- end
- else
- if IsConsole then writeln(Status);
- {$ENDIF}
- case Command of
- CmdStart:
- begin
- Command := CmdList; { get newsgroup list }
- ArtNr := 0
- end;
- CmdList:
- begin
- fNumGroups := -1;
- while Length(Status) > 1 do
- begin
- Inc(fNumGroups);
- i := Pos(#13,Status);
- j := Pos(#10,Status);
- if (i = 0) and (j = 0) then i := Length(Status)
- else
- if j > i then i := j;
- j := 1;
- while (j < i) and (Status[j] > #32) do Inc(j);
- if fNumGroups > 0 then
- begin
- fNewsGroups[fNumGroups-1] := Copy(Status,1,j-1);
- if fNewsGroups[fNumGroups-1] = '' then
- Dec(fNumGroups)
- end;
- Delete(Status,1,i);
- while (Length(Status) > 0) and (Status[1] in [#10,#13]) do Delete(Status,1,1)
- end;
- if (Status = '.') or EOD then Command := CmdDone
- else ArtNr := -1 { continue }
- end;
- CmdJoin:
- begin
- i := Pos(' ',Status);
- Delete(Status,1,i); { status code }
- i := Pos(' ',Status);
- Delete(Status,1,i); { number of articles }
- i := Pos(' ',Status);
- try
- fFirstArticle := StrToInt(Copy(Status,1,i-1))
- except
- fFirstArticle := 1
- end;
- Delete(Status,1,i); { last article }
- i := Pos(' ',Status);
- try
- fLastArticle := StrToInt(Copy(Status,1,i-1))
- except
- fLastArticle := 1
- end;
- fArticles := nil;
- if fLastArticle >= fFirstArticle then
- SetLength(fArticles,fLastArticle-fFirstArticle+1); // allocate
- {$IFDEF DEBUG}
- if Assigned(StatusMemo) then
- StatusMemo.Lines.Add(Space(Indent)+IntToStr(fFirstArticle)+' to '+IntToStr(fLastArticle))
- else
- if IsConsole then writeln(fFirstArticle,' to ',fLastArticle);
- {$ENDIF}
- Command := CmdDone
- end;
- CmdMess:
- begin
- if ArtNr < 0 then { remaining part of article }
- fArticles[-ArtNr-fFirstArticle] := fArticles[-ArtNr-fFirstArticle] + Status
- else
- begin
- i := Pos(#13,Status);
- if i > 0 then
- begin
- Delete(Status,1,i);
- while (Length(Status) > 0) and (Status[1] in [#10,#13]) do Delete(Status,1,1)
- end;
- fArticles[ArtNr-fFirstArticle] := Status
- end;
- if EOD then Command := CmdDone
- else
- ArtNr := -abs(ArtNr) { negative }
- end;
- CmdQuit: Command := CmdDone
- end;
- if Command <> CmdDone then SocketWrite(Sender, Socket)
- end {SocketRead};
-
- procedure TBNNTP.SocketWrite(Sender: TObject; Socket: TCustomWinSocket);
- var
- Send: String;
- begin
- Send := '';
- case Command of
- CmdList: if ArtNr >= 0 then Send := 'LIST';
- CmdJoin: Send := 'GROUP ' + Status;
- CmdMess: if ArtNr > 0 then
- Send := 'ARTICLE ' + IntToStr(ArtNr);
- CmdQuit: Send := 'QUIT'
- end;
- {$IFDEF DEBUG}
- if Assigned(StatusMemo) then
- StatusMemo.Lines.Add(Space(Indent)+'> '+Send)
- else
- if IsConsole then writeln('> '+Send);
- {$ENDIF}
- Socket.SendText(Send + CRLF)
- end {SocketWrite};
-
- procedure TBNNTP.Wait;
- begin
- {$IFDEF DEBUG}
- Inc(Indent);
- if Assigned(StatusMemo) then
- StatusMemo.Lines.Add(Space(Indent)+'Waiting...')
- else
- if IsConsole then writeln('Waiting...');
- Inc(Indent);
- {$ENDIF}
- repeat
- Application.ProcessMessages
- until Command = CmdDone;
- {$IFDEF DEBUG}
- Dec(Indent);
- if Assigned(StatusMemo) then
- StatusMemo.Lines.Add(Space(Indent)+'Done.')
- else
- if IsConsole then writeln('Done.');
- Dec(Indent);
- {$ENDIF}
- end;
-
- procedure TBNNTP.Connect;
- begin
- Command := CmdStart;
- _Socket.Active := False;
- _Socket.Host := fNewsServer;
- _Socket.Open;
- Wait
- end {Connect};
-
- procedure TBNNTP.Disconnect;
- begin
- Command := CmdQuit;
- SocketWrite(Self,WinSocket);
- Wait
- end {Connect};
-
- procedure TBNNTP.JoinNewsGroup(const NewsGroup: String);
- begin
- Status := NewsGroup;
- Command := CmdJoin;
- SocketWrite(Self,WinSocket);
- Wait
- end {JoinNewsGroup};
-
- procedure TBNNTP.ReadArticle(ArticleNr: Integer);
- begin
- ArtNr := ArticleNr;
- Command := CmdMess;
- SocketWrite(Self,WinSocket);
- Wait
- end {ReadArticle};
-
-
- procedure Register;
- begin
- RegisterComponents('Dr.Bob',[TBNNTP])
- end;
-
- end.
-
-